/**
 * @file STL_ThreadPool.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 线程池
 * @version 0.0.1
 * @date 2020-07-16
 * 
 * @coryright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

// #define THRAND_SLEEP_MICRO_SECOND 40*1000
#define THRAND_SLEEP_MICRO_SECOND 100 * 1000

#include "STL_ThreadPool.hpp"
#include "STL_Log.hpp"
#include "STL_Thread.hpp"
#include <string>
#include <functional>
#include <vector>
#include <list>
#include "STL_Mutex.hpp"
#include <unistd.h>

namespace stl
{
    class SingleThread
    {
    public:
        SingleThread(int index) : m_index(index), m_thread("ThreadPool_" + std::to_string(index))
        {
            thread_proc_t proc = std::bind(&SingleThread::thread_proc, this, std::placeholders::_1);
            int r = m_thread.start(proc);
            if (r != 0)
            {
                stl::error("ThreadPool_%d start failed.", index);
            }
            else
            {
                stl::debug("ThreadPool_%d start success.", index);
            }
        }

        ~SingleThread() {}

        int pushTask(const ThreadTask &task)
        {
            Guard g(m_mtx);
            m_tasks.push_back(task);
            return 0;
        }

        int getTaskSize()
        {
            Guard g(m_mtx);
            return m_tasks.size();
        }

    private:
        void thread_proc(void *param)
        {
            while (m_thread.looping())
            {
                do
                { //锁区域
                    Guard g(m_mtx);
                    for (std::list<ThreadTask>::iterator itr = m_tasks.begin(); itr != m_tasks.end();)
                    {
                        if ((*itr)() == -1)
                        {
                            itr = m_tasks.erase(itr); // 失败从现成池删除
                        }
                        else
                        {
                            ++itr;
                        }
                    }
                } while (0);
                usleep(THRAND_SLEEP_MICRO_SECOND);
            }
        }

    private:
        int m_index;
        stl::Mutex m_mtx;
        stl::Thread m_thread;
        std::list<ThreadTask> m_tasks;
    };

    ////////////// ThreadPoolImpl /////////////////////////////////////
    class ThreadPoolImpl
    {
    public:
        ThreadPoolImpl(int num);
        ~ThreadPoolImpl();

        int start(int num);

        int pushTask(const ThreadTask &task);

    private:
        Mutex m_mtx;
        std::vector<SingleThread *> m_pool;
    };

    ThreadPoolImpl::ThreadPoolImpl(int num)
    {
    }

    ThreadPoolImpl::~ThreadPoolImpl()
    {
    }

    int ThreadPoolImpl::start(int num)
    {
        for (int i = 0; i < num; ++i)
        {
            SingleThread *thread = new SingleThread(i);
            m_pool.push_back(thread);
        }
        stl::debug("Start ThreadPool num: %d", num);
        return 0;
    }

    int ThreadPoolImpl::pushTask(const ThreadTask &task)
    {
        stl::Guard g(m_mtx);
        ///< 查找出任务数最少的线程
        int min = 0;
        for (size_t i = 1; i < m_pool.size(); ++i)
        {
            int currentSize = m_pool[min]->getTaskSize();
            int theSize = m_pool[i]->getTaskSize();
            if (currentSize > theSize)
            {
                min = i;
            }
        }
        m_pool[min]->pushTask(task);
        return 0;
    }

    /////////////////////////// ThreadPool //////////////////////////////////
    ThreadPool::ThreadPool() {}

    ThreadPool::~ThreadPool()
    {
        if (m_impl != nullptr)
        {
            delete m_impl;
            m_impl = nullptr;
        }
    }

    ThreadPool *ThreadPool::instance()
    {
        static ThreadPool _inst;
        return &_inst;
    }

    int ThreadPool::start(int num)
    {
        m_impl = new ThreadPoolImpl(num);

        m_impl->start(num);
        return 0;
    }

    int ThreadPool::pushTask(const ThreadTask &task)
    {
        m_impl->pushTask(task);
        return 0;
    }

} // namespace stl
